namespace designpatternsplusplus.decorator.DecoratorParticipants
{
    #region

    using System;
    using designpatternsplus.contracts;

    #endregion

    /// <summary>
    /// The standard abstract base for decorators..But ++
    /// Perhaps a first look would be confusing but when
    /// teams understand delegates I find the funcational
    /// aspects can dramatically increase productivity
    /// but the initial curve is a small hurdle.
    /// 
    /// I am using this as I have used it for almost two years now
    /// It is a production, SP1 even entrenched language enhancement
    /// that were I not to use it, you could not see some of the 
    /// personal progress I have made in teaching patterns using these
    /// new techniques
    /// </summary>
    public abstract class SellableItemDecoratorBase : IProductService
    {
        /// <summary>
        /// As expected.. THis is our wrapped concrete item
        /// we then decorate with tax calcs (as delegates)
        /// </summary>
        protected readonly IProductService _ProductDecorated;

        /// <summary>
        /// This is the key algorithm abstract one level up
        /// for the wrapper
        /// </summary>
        protected Func<IProductService, double> decoratorDelegate;

        /// <summary>
        /// Initializes a new instance of the <see cref="SellableItemDecoratorBase"/> class.
        /// Standard decorator wrapper
        /// </summary>
        /// <param name="resolveProduct">The resolve product.</param>
        protected SellableItemDecoratorBase(IProductService resolveProduct)
            : this(resolveProduct, null) {}

        protected SellableItemDecoratorBase
            (IProductService resolveProduct, Func<IProductService, double> delegateItemIn)
        {
            _ProductDecorated = resolveProduct;
            decoratorDelegate = delegateItemIn;
        }

        #region IProductService Members

        /// <summary>
        /// Gets the type of the sales item.
        /// </summary>
        /// <value>The type of the sales item.</value>
        /// Delegate the calls to the root 'concrete item decorated'
        public ProductType Type
        {
            get { return _ProductDecorated.Type; }
        }

        /// <summary>
        /// Gets or sets the quantity.
        /// </summary>
        /// <value>The quantity.</value>
        public int Quantity
        {
            get { return _ProductDecorated.Quantity; }
            set { throw new NotImplementedException(); }
        }

        public bool IsImported
        {
            get { return _ProductDecorated.IsImported; }
            set { throw new NotImplementedException(); }
        }

        public double BaseAmount
        {
            get { return _ProductDecorated.BaseAmount; }
        }

        public string Sku
        {
            get { return _ProductDecorated.Sku; }
        }

        public ISkuDetails MasterDetails
        {
            get { return _ProductDecorated.MasterDetails; }
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return String.Format
                ("{0}  {1}  Qty= {2}", Amount().ToString("C"), Type.Name, Quantity);
        }

        public abstract double Amount();

        #endregion
    }
}